#pragma once

#ifndef _CORE_CORE_XML_HANDLER_H_
#define _CORE_CORE_XML_HANDLER_H_

#include "Poco\SAX\SAXParser.h"
#include "Poco\SAX\ContentHandler.h"
#include "Poco\SAX\Attributes.h"
#include "Poco\SAX\Locator.h"
#include "Poco\Exception.h"
#include "Poco\BasicEvent.h"


namespace ExamSystem
{
    using Poco::XML::ContentHandler;
    using Poco::XML::SAXParser;
    using Poco::XML::XMLReader;
    using Poco::XML::XMLString;
    using Poco::XML::XMLChar;
    using Poco::XML::ContentHandler;
    using Poco::XML::LexicalHandler;
    using Poco::XML::Attributes;
    using Poco::XML::Locator;
    using Poco::BasicEvent;

    class CCoreXMLHandlerManager;
    class CStanzaHandler;
    class CXMLConnection;

    /**************************************************************************\
     Component:     CCoreXMLHandler
     Description:   
        This class is a ContactHandler for a SAXParser.
    \**************************************************************************/
    class CCoreXMLHandler : public ContentHandler
    {    
        friend class CCoreXMLHandlerManager;
    protected:
        CCoreXMLHandler(CCoreXMLHandlerManager *manager);

    public:
        // ContentHandler, see Poco\SAX\ContentHandler.h for more information
        void setDocumentLocator(const Locator* loc);
        void startElement(const XMLString& uri, const XMLString& localName, const XMLString& qname, const Attributes& attributes);
        void endElement(const XMLString& uri, const XMLString& localName, const XMLString& qname);
        void characters(const XMLChar ch[], int start, int length);

        // the following methods are ignored
        void startDocument();
        void endDocument();
        void ignorableWhitespace(const XMLChar ch[], int start, int length);
        void processingInstruction(const XMLString& target, const XMLString& data);
        void startPrefixMapping(const XMLString& prefix, const XMLString& uri);
        void endPrefixMapping(const XMLString& prefix);
        void skippedEntity(const XMLString& name);

    public:
        // register a stanza handler. 
        // handler registered here has the priority
        void RegisterStanzaHandler(const std::string &type, CStanzaHandler *handler);

        // attached this handler to a xml connection
        // the attached connection will be passed to the stanza handlers
        void AttachToConnection(CXMLConnection *connection);

    protected:
        // get the registered stanza handler 
        void GetStanzaHandler(const std::string &type, std::vector<CStanzaHandler *> &handlers) const;

    public:
        // events
        BasicEvent<int> eventInvalidStream;
        BasicEvent<int> eventStreamStart;
        BasicEvent<int> eventStreamEnd;

    private:
        const Locator* m_locator;

        // a flag that identifies the xml stream has started
        bool m_flagStreamStart;

        // the manager
        CCoreXMLHandlerManager *m_handlerManager;
        
        // current stanza 
        std::vector<CStanzaHandler *> m_currentStanzaHandler;

        // stanza handlers
        std::multimap<std::string, CStanzaHandler *> m_registeredHandlers;

        // attached connection
        CXMLConnection *m_attachedConnection;
    };

}

#endif